	/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __GPIO_HPP
#define __GPIO_HPP

#define GPIO_LOG(x)
#define GPIO_ERR_GPIO_ACCESS_DENIED        "GPIO, ERR, ACCESS DENIED\n"  
#define GPIO_ERR_PIN_IS_NOT_AVAILABLE      "GPIO, ERR, PIN IS NOT AVAILABLE\n"  

#define GPIO_Numbers_ALL                   0x05        /* GPIO A..D, F */

#define GPIO_SWD_PROTECTED        
#define GPIO_SWD_PORT                       GPIO_A
#define GPIO_SWD_DIO                        (1<<13)
#define GPIO_SWD_CLK                        (1<<14)

/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx.h"
#include "Global_types.h"

/* Exported objects ----------------------------------------------------------*/
#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected    */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected    */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected    */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected    */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected    */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected    */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected    */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected    */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected    */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected    */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected   */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected   */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected   */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected   */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected   */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected   */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

typedef enum {
	GPIO_A = 0, GPIO_B = 1, GPIO_C = 2, GPIO_D = 3, GPIO_F = 4,
} GPIO_NUM_type;

typedef enum {
	GPIO_PuPd_NOPULL = 0x00,
	GPIO_OType_OD = 0x01,
	GPIO_PuPd_UP = 0x04,
	GPIO_PuPd_DOWN = 0x08,
} GPIO_OUT_type;

typedef enum {
	GPIO_Mode_IN = 0x00,
	GPIO_Mode_OUT = 0x01,
	GPIO_Mode_AN = 0x03,
	GPIO_Mode_AF_0 = 0x02, /* WKUP, EVENTOUT, TIM15, SPI1, TIM17, MCO, SWDAT, SWCLK, TIM14, BOOT, USART1, CEC, IR_OUT, SPI2 */
	GPIO_Mode_AF_1 = 0x06, /* CEC, TIM3, USART1, USART2, EVENTOUT, I2C1, I2C2, TIM15 */
	GPIO_Mode_AF_2 = 0x0A, /* TIM2, TIM1, EVENTOUT, TIM16, TIM17 */
	GPIO_Mode_AF_3 = 0x0E, /* TS, I2C1, TIM15, EVENTOUT */
	GPIO_Mode_AF_4 = 0x12, /* TIM14 */
	GPIO_Mode_AF_5 = 0x16, /* TIM16, TIM17 */
	GPIO_Mode_AF_6 = 0x1A, /* EVENTOUT */
	GPIO_Mode_AF_7 = 0x1E, /* COMP1 OUT and COMP2 OUT */
} GPIO_MODE_type;

typedef enum {
	GPIO_Speed_2MHz = 0, GPIO_Speed_10MHz = 1, GPIO_Speed_50MHz = 3,
} GPIOSpeed_type;

typedef struct {
	GPIO_TypeDef *Reg;
	u32 RccMsk;
	u16 AccessMsk;
} GPIO_ACCESS_type;

/* Class definition ----------------------------------------------------------*/
class TGPIO_manager {
private:
	static u8 Ref;
	static GPIO_ACCESS_type Gpio[GPIO_Numbers_ALL];

public:
	/* Class constructor */
	TGPIO_manager();

	/* Exported function */
	static u32 Init(GPIO_NUM_type N, u16 PinMsk, GPIO_MODE_type Mode,
			GPIO_OUT_type Out);
	static u32 DeInit(GPIO_NUM_type N, u16 PinMsk);

	static inline u32 Read(GPIO_NUM_type N) {
		return Gpio[N].Reg->IDR;
	}
	;

	inline void Write(GPIO_NUM_type N, u16 PinMsk, u16 State) {
		if (State != 0)
			Set(N, PinMsk);
		else
			Clr(N, PinMsk);
	}
	;

	static inline void Set(GPIO_NUM_type N, u16 PinMsk) {
		Gpio[N].Reg->BSRR = (PinMsk & Gpio[N].AccessMsk);
	}
	;

	static inline void Clr(GPIO_NUM_type N, u16 PinMsk) {
		Gpio[N].Reg->BSRR = ((PinMsk & Gpio[N].AccessMsk) << 16);
	}
	;

	static inline void Invert(GPIO_NUM_type N, u16 PinMsk) {
		Gpio[N].Reg->ODR ^= (PinMsk & Gpio[N].AccessMsk);
	}
};

#endif
/* End of file ---------------------------------------------------------------*/
